/*
 * Logout.java
 * 
 * Version information
 * 
 * Feb 17, 2006
 * 
 * Copyright (c) AmSoft Systems, 2006
 */
package net.amsoft.iservice.isso.webapp.struts.action;

import java.net.URLEncoder;
import java.util.HashMap;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.amsoft.iservice.isso.client.ISSOClient;
import net.amsoft.iservice.isso.client.SAMLDataObject;
import net.amsoft.iservice.isso.service.ISSOService;
import net.amsoft.iservice.isso.webapp.dataObject.IBrokerData;
import net.amsoft.iservice.isso.webapp.dataObject.LoginData;
import net.amsoft.iservice.isso.webapp.dataObject.SPData;
import net.amsoft.iservice.isso.webapp.struts.form.LogoutForm;
import net.amsoft.iservice.util.IServiceUtil;
import net.amsoft.iservice.util.MetaData;
import net.amsoft.iservice.isso.util.ISSOConstants;
import net.amsoft.iservice.isso.util.SAMLProcessor;
import net.amsoft.iservice.util.ResolverClient;
import net.amsoft.iservice.util.exception.IServiceException;

import org.apache.log4j.Logger;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionMessage;
import org.apache.struts.action.ActionMessages;

/**
 * This is the action, which will get invoked on selecting Confirm option in
 * Confirm Logout Screen, which will invalidate global session of the principal,
 * store a Logout Response return its Artifact to the SP
 * 
 * @author rahul
 */
public class Logout extends BaseAction {
	private static Logger oLogger=Logger.getLogger(Logout.class);
    public ActionForward process(ActionMapping oMapping, ActionForm oForm,
            HttpServletRequest oRequest, HttpServletResponse oResponse)
            throws Exception {
    	oLogger.info("process() : entry");
        // get the session Objects
        LoginData oLoginData = (LoginData) oRequest.getSession(false)
                .getAttribute(ISSOConstants.SESSION_LOGIN_OBJ);
        HashMap ohSPData = (HashMap) oRequest.getSession(false).getAttribute(
                ISSOConstants.SESSION_LOGIN_HASH_OBJ);
        LogoutForm oLogoutForm = (LogoutForm) oForm;
        // String sSPXri = oRequest.getParameter(ISSOConstants.REQ_PARAM_SPXRI);

        String sSPXri = oLogoutForm.getSpXri();
        SPData oSpData = (SPData) ohSPData.get(sSPXri);
        SAMLDataObject oReceivedLogoutRequest = oSpData.getSAMLData();
        ActionMessages oMessages = new ActionErrors();
        try {
            String sStep = oRequest
                    .getParameter(ISSOConstants.REQ_PARAM_ACTION);
            oLogger.info("process() : Req Param=" + sStep);
            // Check if parameter is null due to direct access of page
            if (sStep != null) {
                IBrokerData oIBrokerData = (IBrokerData) oRequest.getSession()
                        .getAttribute(ISSOConstants.SESSION_IBROKER_OBJ);
                // String sSPXri = oLogoutForm.getSpxri();
                oLogger.info("process() : spXRI=" + sSPXri);
                if (sStep.equals(ISSOConstants.REQ_PARAM_ACTION_LOGOUT)) {
                	oLogger.info("process() : Message : In logout block");
                	if (sSPXri == null
                            || sSPXri.trim().length() == 0
                            || checkSpecialSPCase(oRequest, oRequest
                                    .getServerName(), sSPXri)) {
                        ISSOService.logout(oLoginData.getSessionCookie());
                        oLogger.info("process() : Logout=Success, SessionCookie="+ oLoginData.getSessionCookie());
                        removeCookie(oResponse, true);
                        oRequest.getSession(false).invalidate();
                        loadIBrokerData(oIBrokerData, oRequest.getServerName());
                        oRequest.getSession().setAttribute(ISSOConstants.SESSION_IBROKER_OBJ, oIBrokerData);
                        oMessages.add(ActionMessages.GLOBAL_MESSAGE,
                                new ActionMessage(
                                        ISSOConstants.MSG_LOGOUT_SUCCESS));
                        saveErrors(oRequest.getSession(), oMessages);
                        oLogger.info("process() : Message : Exit,  Iname Forward");
                        return oMapping.findForward(ISSOConstants.INAME_FWD);
                    } else {
                        ISSOService.logout(oReceivedLogoutRequest
                                .getSessionIndex());
                        oLogger.info("process() : Logout=Success, SessionIndex="+ oReceivedLogoutRequest.getSessionIndex());
                        oRequest.getSession(false).invalidate();
                        loadIBrokerData(oIBrokerData, oRequest.getServerName());
                        oRequest.getSession()
                                .setAttribute(
                                        ISSOConstants.SESSION_IBROKER_OBJ,
                                        oIBrokerData);
                        removeCookie(oResponse, true);
                        return doSPLogout(oSpData, oLoginData, oRequest
                                .getServerName(), 0);
                    }
                } else if (sStep.equals(ISSOConstants.REQ_PARAM_ACTION_CANCEL)) {
                    return doSPLogout(oSpData, oLoginData, oRequest
                            .getServerName(), 2);
                } else {
                    // Reqest received with unknown request parameter value
                    oMessages
                            .add(ActionMessages.GLOBAL_MESSAGE,
                                    new ActionMessage(
                                            ISSOConstants.ERR_INVALID_REQUEST));
                    saveErrors(oRequest, oMessages);
                    oLogger.error("process() : Exit, Message : Invalid Request, Forward to Message page");
                    return oMapping.findForward(ISSOConstants.MESSAGE_FWD);
                }
            } else {
                // Reqest received without request parameter
                oMessages.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage(
                        ISSOConstants.ERR_INVALID_REQUEST));
                saveErrors(oRequest.getSession(), oMessages);
                oLogger.debug("process() : Exit, Message : Request without params, Forward to Message page");
                return oMapping.findForward(ISSOConstants.MESSAGE_FWD);
            }

        } catch (IServiceException e) {
            // Redirect to login page if directly accessed
            if (e.getErrorCode() == 2028) {
            	oLogger.error("process() : Exit, Exception=2028, Forward to i-name page"); 
                return oMapping.findForward(ISSOConstants.INAME_FWD);
            }

            oMessages.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage(e
                    .getMessage(), false));
            saveErrors(oRequest, oMessages);
            oLogger.info("process() : Exit");
            return oMapping.findForward(ISSOConstants.MESSAGE_FWD);
        }
    } // process() ends

    private ActionForward doSPLogout(SPData oSpData, LoginData oLoginData,
            String sServerName, int iLogoutStatus) throws IServiceException {
        // create logout response, save it and return artifact
    	oLogger.info("doSPLogout() entry , LogoutStatus="+ iLogoutStatus);
        
        MetaData oMetaData = ResolverClient.getFinalMetaData(oSpData
                .getSAMLData().getSubjectNameIDNameQualifier());

        String sArtifact = createArtifact(oMetaData.getProviderID());

        ISSOService.saveSAMLResponse(sArtifact, null, SAMLProcessor
                .serializeLogoutResponse(oSpData.getSAMLData().getID(), "",
                        iLogoutStatus,
                        ISSOConstants.getProviderID(sServerName), IServiceUtil
                                .generateUniqueID()));

        String sArtifactDocXML = SAMLProcessor
                .serializeArtifactDocument(sArtifact);

        oMetaData = ResolverClient.getSPMetaData(oSpData.getSAMLData()
                .getSPXri());
        String sSPLogoutServiceURL = oMetaData.getISLOUrl();
        try {
        	oLogger.info("doSPLogout(): Exit, Message=Redirect to " + sSPLogoutServiceURL);
            return new ActionForward(sSPLogoutServiceURL + "?"
                    + ISSOClient.PARAM_SAML_ART + "="
                    + URLEncoder.encode(sArtifactDocXML, "UTF-8") + "&"
                    + ISSOClient.PARAM_RELAY_STATE + "="
                    + URLEncoder.encode(oSpData.getRelayState(), "UTF-8"), true);
        } catch (Exception e) {
            throw new IServiceException(ISSOConstants.getError(102), 102);
        }
    }// doSPLogout() ends
}